package tman.simulator.snapshot;

import java.util.HashMap;

import common.peer.PeerData;

import common.configuration.Global;
import common.peer.PeerAddress;

public class StateUtil {
	private HashMap<Integer, Integer> HopCountDistr = new HashMap<Integer, Integer>();
	private HashMap<Integer, Integer> OptimalHopCountDistr = new HashMap<Integer, Integer>();
	private HashMap<Integer, HashMap<Integer, Integer>> DetailedHopCountDistr = new HashMap<Integer, HashMap<Integer, Integer>>();
	private Double totalError;
	private float avgLatency;
	private HashMap<String, Integer> eventCounts = new HashMap<String, Integer>();
	
	public StateUtil(HashMap<PeerAddress, PeerData> alivePeers)
	{
		calcOptimalHopCountDistr();
		calcHopCountDistr(alivePeers);
		calcDetailedHopCountDistr(alivePeers);
		calcTotalError();
		calcTotalEvents(alivePeers);
		avgLatency = calcAverageLatency(alivePeers);
	}
	
    //-------------------------------------------------------------------
	
	public void calcTotalEvents(HashMap<PeerAddress, PeerData> alivePeers)
	{
		for(PeerAddress peer: alivePeers.keySet())
		{
			HashMap<String, Integer> ecs = alivePeers.get(peer).getEventCounts();
			for(String eventType: ecs.keySet())
			{
				if(eventCounts.get(eventType) == null)
					eventCounts.put(eventType, ecs.get(eventType));
				else
					eventCounts.put(eventType, eventCounts.get(eventType)+ecs.get(eventType));
			}
		}
	}
	public Double getTotalError()
	{
		return totalError;
	}
	
	public HashMap<String, Integer> getTotalEvents()
	{
		return eventCounts;
	}
	
	public HashMap<Integer, Integer> getHopCountDistr()
	{
		return HopCountDistr;
	}
	
	public float getAvgLatency()
	{
		return avgLatency;
	}
	
	public HashMap<Integer, Integer> getOptimalHopCountDistr()
	{
		return OptimalHopCountDistr;
	}
	
	public HashMap<Integer, HashMap<Integer, Integer>> getDetailedHopCountDistr()
	{
		return DetailedHopCountDistr;
	}
	
	private void calcOptimalHopCountDistr() {
    	CentralSolution LetsSolveThis = new CentralSolution();
    	for(Integer i: Global.odDistr.keySet())
    	{
    		//System.out.println("OD frequency of " + i + " is: " + Global.odDistr.get(i));
        	LetsSolveThis.addNodes(i, Global.odDistr.get(i));
    	}
    	
    	LetsSolveThis.addNodes(Global.srcOD, 1);
    	LetsSolveThis.startAndRun();
    	OptimalHopCountDistr = LetsSolveThis.getDistr();
	}
	
	private void calcTotalError()
	{
    	totalError = 0.0;
    	Double denom = 0.0;
    	for(Integer od: OptimalHopCountDistr.keySet())
    	{
    		int diff = 0;
    		int freq = OptimalHopCountDistr.get(od);
    		if(HopCountDistr.get(od) != null)
    		{
    			diff = Math.abs(freq - HopCountDistr.get(od));    					
    		}
    		else diff = freq;
    		
    		denom += freq;
    		totalError += diff;
    	}
    	totalError = totalError/denom*100.0;
	}
    private void calcHopCountDistr(HashMap<PeerAddress, PeerData> alivePeers) {
        PeerAddress[] peersList = new PeerAddress[alivePeers.size()];
        alivePeers.keySet().toArray(peersList);
        
    	HopCountDistr = new HashMap<Integer, Integer>();
     	//System.out.println(peersList.length);
    	for(int i=0; i<peersList.length; i++)
    	{
    		PeerData peerData = alivePeers.get(peersList[i]);
    		Integer hc = (int)Math.ceil(peerData.getHopcount());
    		if(HopCountDistr.get(hc) == null)
    			HopCountDistr.put(hc, 1);
    		else
    			HopCountDistr.put(hc, HopCountDistr.get(hc) + 1);
    	}
    }
    
    private void calcDetailedHopCountDistr(HashMap<PeerAddress, PeerData> alivePeers) {
        PeerAddress[] peersList = new PeerAddress[alivePeers.size()];
        alivePeers.keySet().toArray(peersList);
        
    	for(int i=0; i<peersList.length; i++)
    	{
    		PeerData peerData = alivePeers.get(peersList[i]);
    		Integer hc = (int)Math.ceil(peerData.getHopcount());
    		Integer OD = peersList[i].getBandwidth();
    		if(DetailedHopCountDistr.get(hc) == null)
    		{
    			HashMap<Integer, Integer> temp = new HashMap<Integer, Integer>();
    			temp.put(OD, 1);
    			DetailedHopCountDistr.put(hc, temp);
    		}
    		else
    		{
    			HashMap<Integer, Integer> temp = DetailedHopCountDistr.get(hc);
    			if(temp.get(OD)==null)
    				temp.put(OD, 1);
    			else
    			{
    				temp.put(OD, temp.get(OD)+1);
    				//System.out.println("OD:" + OD + " freq:" + (temp.get(OD)+1));
    			}
    			DetailedHopCountDistr.put(hc, temp);

    		}
    		
    	}
    }
    
    private float calcAverageLatency(HashMap<PeerAddress, PeerData> alivePeers)
    {
    	float totalLatency = 0;
		for(PeerAddress peer: alivePeers.keySet())
		{
			totalLatency += alivePeers.get(peer).getHopcount();
		}
		
		return totalLatency/alivePeers.size();
    }

}
